#include "esp_mqtt_impl.h"
#include "mqtt_client.h" 
#include "esp_log.h"
#include <string>
#include <memory>
#include <esp_crt_bundle.h>//支持mqtts连接时启用

#define TAG "EspMqttImpl" // 日志标签

// 为连接状态定义事件位，类似于 esp_mqtt.cpp
#define MQTT_CONNECTED_BIT BIT0    // MQTT 连接成功事件位
#define MQTT_DISCONNECTED_BIT BIT1 // MQTT 断开连接事件位 (为对称性添加，尽管在等待时不像 esp_mqtt.cpp 那样严格使用)
#define MQTT_ERROR_BIT BIT2        // MQTT 错误事件位
#define MQTT_CONNECT_TIMEOUT_MS 10000 // 连接尝试超时时间 (毫秒)

// EspMqttImpl 构造函数
EspMqttImpl::EspMqttImpl() {
    mqtt_event_group_ = xEventGroupCreate(); // 创建事件组
    if (mqtt_event_group_ == nullptr) {
        ESP_LOGE(TAG, "Failed to create event group"); // 创建事件组失败
        // 处理错误，例如抛出异常或设置错误状态
    }
    ESP_LOGI(TAG, "MQTT客户端实例创建完成");
}

// EspMqttImpl 析构函数
EspMqttImpl::~EspMqttImpl() {
    Disconnect(); // 断开连接
    
    if (mqtt_event_group_ != nullptr) {
        vEventGroupDelete(mqtt_event_group_); // 删除事件组
        mqtt_event_group_ = nullptr;
    }
    
    ESP_LOGI(TAG, "MQTT客户端实例销毁完成");
}

// 静态事件处理函数
void EspMqttImpl::mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
    EspMqttImpl* impl_instance = static_cast<EspMqttImpl*>(handler_args); // 获取 EspMqttImpl 实例指针
    if (impl_instance) {
        impl_instance->internal_event_handler(base, event_id, event_data); // 调用成员事件处理函数
    } else {
        ESP_LOGE(TAG, "实例指针为空，无法处理事件");
    }
}

// 成员事件处理函数
void EspMqttImpl::internal_event_handler(esp_event_base_t base, int32_t event_id, void *event_data) {
    esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; // 获取 MQTT 事件句柄
    switch ((esp_mqtt_event_id_t)event_id) { // 根据事件 ID 处理
        case MQTT_EVENT_CONNECTED: // 连接成功事件
            handle_connected(event);
            if (mqtt_event_group_) {
                xEventGroupSetBits(mqtt_event_group_, MQTT_CONNECTED_BIT);
            }
            break;
        case MQTT_EVENT_DISCONNECTED: // 断开连接事件
            handle_disconnected(event);
            if (mqtt_event_group_) {
                xEventGroupSetBits(mqtt_event_group_, MQTT_DISCONNECTED_BIT);
            }
            break;
        case MQTT_EVENT_DATA: // 收到数据事件
            handle_data(event);
            break;
        case MQTT_EVENT_SUBSCRIBED: // 订阅成功事件
            handle_subscribed(event);
            break;
        case MQTT_EVENT_UNSUBSCRIBED: // 取消订阅成功事件
            handle_unsubscribed(event);
            break;
        case MQTT_EVENT_PUBLISHED: // 发布成功事件
            handle_published(event);
            break;
        case MQTT_EVENT_ERROR: // 发生错误事件
            handle_error(event);
            if (mqtt_event_group_) {
                xEventGroupSetBits(mqtt_event_group_, MQTT_ERROR_BIT);
            }
            break;
        case MQTT_EVENT_BEFORE_CONNECT: // 连接前事件
            ESP_LOGI(TAG, "准备连接MQTT代理");
            break;
        default: // 其他事件
            break;
    }
}

// 连接到 MQTT 代理
bool EspMqttImpl::Connect(const std::string broker_address, int broker_port, const std::string client_id, const std::string username, const std::string password) {
    ESP_LOGI(TAG, "开始连接MQTT代理: %s:%d", broker_address.c_str(), broker_port);
    
    if (mqtt_client_handle_) { // 如果客户端已初始化或已连接
        ESP_LOGW(TAG, "Already connected or client initialized. Disconnect first."); // 先断开连接
        Disconnect(); // 清理现有客户端再重新连接
    }

    if (mqtt_event_group_ == nullptr) { // 确保事件组有效
        ESP_LOGE(TAG, "Event group not initialized!"); // 事件组未初始化
        return false;
    }
    
    xEventGroupClearBits(mqtt_event_group_, MQTT_CONNECTED_BIT | MQTT_DISCONNECTED_BIT | MQTT_ERROR_BIT); // 清除事件位

    esp_mqtt_client_config_t mqtt_cfg = {}; // MQTT 客户端配置
    std::string broker_uri_str; // 代理 URI 字符串

    /**
     * @brief 设置 MQTT 地址
     * 直接设置全URL和设置hostname+port+transport，二选一，否则报错
     */
    //====================================================================================================================
    if (broker_port == 8883) { // SSL/TLS 连接
        ESP_LOGI(TAG, "配置MQTTS连接");
        ESP_LOGW(TAG,"连接的服务器必须要支持加密才行，否在会提示找不到可以用的ca证书"); 
        broker_uri_str = "mqtts://" + broker_address;
        // mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_SSL; // 设置传输层为 SSL  //全url和设置协议二选一
        mqtt_cfg.broker.verification.crt_bundle_attach = esp_crt_bundle_attach; // 附加 CA 证书包
    } else { // TCP 连接
        ESP_LOGI(TAG, "配置MQTT连接");
        broker_uri_str = "mqtt://" + broker_address;
        // mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_TCP; // 设置传输层为 TCP  //全url和设置协议二选一
    }
    if (broker_port != 0 && broker_port != 1883 && broker_port != 8883) { // 如果端口不是标准端口，则附加到 URI
         broker_uri_str += ":" + std::to_string(broker_port);
    }
    mqtt_cfg.broker.address.uri = broker_uri_str.c_str(); // 设置代理 URI
    //====================================================================================================================

    /**
     * @brief MQTT 配置
     * 直接设置全URL和设置hostname+port+transport，二选一，否则报错
     */
    //====================================================================================================================
    if (!client_id.empty()) {
        mqtt_cfg.credentials.client_id = client_id.c_str();
    }
    if (!username.empty()) {
        mqtt_cfg.credentials.username = username.c_str();
    }
    if (!password.empty()) {
        mqtt_cfg.credentials.authentication.password = password.c_str();
    }
    
    mqtt_cfg.session.protocol_ver = MQTT_PROTOCOL_V_3_1_1; // 设置 MQTT 协议版本
    mqtt_cfg.session.keepalive = this->keep_alive_seconds_; // 设置心跳间隔
    //====================================================================================================================

    mqtt_client_handle_ = esp_mqtt_client_init(&mqtt_cfg); // 初始化 MQTT 客户端
    if (!mqtt_client_handle_) {
        ESP_LOGE(TAG, "Failed to initialize MQTT client."); // 初始化 MQTT 客户端失败
        return false;
    }

    esp_err_t err = esp_mqtt_client_register_event(mqtt_client_handle_, MQTT_EVENT_ANY, mqtt_event_handler, this); // 注册 MQTT 事件处理函数
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to register MQTT event handler: %s", esp_err_to_name(err)); // 注册 MQTT 事件处理函数失败
        esp_mqtt_client_destroy(mqtt_client_handle_); // 销毁 MQTT 客户端
        mqtt_client_handle_ = nullptr;
        return false;
    }

    err = esp_mqtt_client_start(mqtt_client_handle_); // 启动 MQTT 客户端
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start MQTT client: %s", esp_err_to_name(err)); // 启动 MQTT 客户端失败
        esp_mqtt_client_destroy(mqtt_client_handle_); // 销毁 MQTT 客户端
        mqtt_client_handle_ = nullptr;
        return false;
    }

    ESP_LOGI(TAG, "MQTT客户端已启动，等待连接");

    EventBits_t bits = xEventGroupWaitBits(mqtt_event_group_, // 等待事件位
                                           MQTT_CONNECTED_BIT | MQTT_ERROR_BIT | MQTT_DISCONNECTED_BIT, // 等待连接成功、错误或明确断开连接
                                           pdTRUE,    // 退出时清除事件位
                                           pdFALSE,   // 等待任何一个事件位 (或逻辑)
                                           pdMS_TO_TICKS(MQTT_CONNECT_TIMEOUT_MS)); // 超时时间

    //第一次连接，发生错误或者超时则调用Disconnect()清理mqtt客户端 //修改，就算第一次连接失败，也要不清理mqtt客户端
    if (bits & MQTT_CONNECTED_BIT) { // 连接成功
        ESP_LOGI(TAG, "MQTT连接建立成功");
        return true;
    } else if (bits & MQTT_ERROR_BIT) { // 连接错误
    /**
     * 为什么需要调用Disconnect()：
     * 客户端可能处于半初始化状态
     * ESP-IDF MQTT客户端可能已经启动但连接失败
     * 需要主动清理mqtt_client_handle_等资源
     * 确保状态完全重置
     */
        ESP_LOGE(TAG, "MQTT connection error."); // MQTT 连接错误
        // Disconnect(); // 发生错误时清理
        return false;
    } else if (bits & MQTT_DISCONNECTED_BIT) { // 在等待连接时断开
    /**
     *情况A：自然断开连接
     *  收到了MQTT_EVENT_DISCONNECTED事件
     *  ESP-IDF MQTT客户端内部已经处理了断开
     *  资源已经被正确清理
     *  handle_disconnected()已经被调用，状态已更新
     *情况B：主动断开连接
     *  其他线程调用了Disconnect()方法
     *  资源清理工作已经完成
     *  再次调用Disconnect()是冗余的
     *关键区别
     *  | 场景 | 客户端状态 | 资源清理状态 | 是否需要Disconnect() |
     *  |------|------------|--------------|---------------------|
     *  | ERROR | 半初始化 | 未清理 | ✅ 需要 |
     *  | 超时 | 启动但无响应 | 未清理 | ✅ 需要 |
     *  | DISCONNECTED | 已断开 | 已清理 | ❌ 不需要 |
     *避免重复清理
     *  在MQTT_DISCONNECTED_BIT情况下调用Disconnect()可能会导致：
     *  重复清理已经为空的mqtt_client_handle_
     *  不必要的日志输出
     *  轻微的性能损耗
     */
        ESP_LOGW(TAG, "MQTT disconnected while waiting for connection."); // MQTT 在等待连接时断开
        return false; // 或作为错误处理
    } else { // 连接超时
    /**
     * 为什么需要调用Disconnect()：
     * 客户端已经启动(esp_mqtt_client_start()被调用)
     * 但没有收到任何响应事件
     * 客户端可能还在尝试连接，需要主动停止
     * 需要清理资源避免内存泄漏
     */
        ESP_LOGW(TAG, "MQTT连接超时");
        // Disconnect(); // 超时时清理
        return false;
    }
}

// 断开 MQTT 连接
void EspMqttImpl::Disconnect() {
    if (mqtt_client_handle_) { // 如果客户端句柄有效
        ESP_LOGI(TAG, "断开MQTT连接");
        esp_mqtt_client_stop(mqtt_client_handle_);      // 首先停止客户端
        esp_mqtt_client_destroy(mqtt_client_handle_); // 然后销毁客户端
        mqtt_client_handle_ = nullptr;
    }
    if (is_connected_) {
        //is_connected_会被handle_disconnected回调设置为false，没有被设置为false，则代表手动断开连接，或者断开连接事件没有触发
        is_connected_ = false;
        if (on_disconnected_callback_) {
            // on_disconnected_callback_(); // 调用回调函数
        }
    }
    /**
     *    自然断开：网络问题、服务器断开等导致的MQTT_EVENT_DISCONNECTED事件
     *    主动断开：调用Disconnect()方法主动断开连接
     *  避免等待超时
     *    如果在Connect()等待连接的过程中调用了Disconnect()：
     *    没有这个信号：xEventGroupWaitBits会一直等待到超时
     *    有了这个信号：可以立即从等待中退出，提供更好的响应性
     *  保持事件处理的一致性
     *    确保无论是自然断开还是主动断开，事件组都能正确反映当前状态，让其他等待该事件的任务能够及时响应。
     *    具体场景
     *      假设这样的时序：
     *      线程A调用Connect()，开始等待连接结果
     *      线程B调用Disconnect()主动断开
     *      如果没有在Disconnect()中设置MQTT_DISCONNECTED_BIT，线程A会一直等待到超时
     *      有了这个信号，线程A可以立即知道连接已经被主动断开
     *  所以这个MQTT_DISCONNECTED_BIT的作用是确保多线程环境下的同步和及时响应。
     */
    if (mqtt_event_group_) {
         xEventGroupSetBits(mqtt_event_group_, MQTT_DISCONNECTED_BIT); // 发送断开连接信号
    }
}

// 发布消息
bool EspMqttImpl::Publish(const std::string topic, const std::string payload, int qos) {
    if (!IsConnected() || !mqtt_client_handle_) { // 如果未连接或客户端未初始化
        ESP_LOGE(TAG, "Not connected or client not initialized, cannot publish."); // 未连接或客户端未初始化，无法发布
        return false;
    }
    
    int msg_id = esp_mqtt_client_publish(mqtt_client_handle_, topic.c_str(), payload.data(), payload.length(), qos, 0); // 发布消息
    
    bool success = (msg_id != -1);
    if (success) {
        ESP_LOGI(TAG, "消息发布成功: %s", topic.c_str());
    } else {
        ESP_LOGE(TAG, "消息发布失败: %s", topic.c_str());
    }
    
    return success; // esp_mqtt_client_publish 错误时返回 -1
}

// 订阅主题
bool EspMqttImpl::Subscribe(const std::string topic, int qos) {
    if (!IsConnected() || !mqtt_client_handle_) { // 如果未连接或客户端未初始化
        ESP_LOGE(TAG, "Not connected or client not initialized, cannot subscribe."); // 未连接或客户端未初始化，无法订阅
        return false;
    }
    
    int msg_id = esp_mqtt_client_subscribe(mqtt_client_handle_, topic.c_str(), qos); // 订阅主题
    
    bool success = (msg_id != -1);
    if (success) {
        ESP_LOGI(TAG, "主题订阅成功: %s", topic.c_str());
    } else {
        ESP_LOGE(TAG, "主题订阅失败: %s", topic.c_str());
    }
    
    return success; // esp_mqtt_client_subscribe 错误时返回 -1
}

// 取消订阅主题
bool EspMqttImpl::Unsubscribe(const std::string topic) {
    if (!IsConnected() || !mqtt_client_handle_) { // 如果未连接或客户端未初始化
        ESP_LOGE(TAG, "Not connected or client not initialized, cannot unsubscribe."); // 未连接或客户端未初始化，无法取消订阅
        return false;
    }
    
    int msg_id = esp_mqtt_client_unsubscribe(mqtt_client_handle_, topic.c_str()); // 取消订阅主题
    
    bool success = (msg_id != -1);
    if (success) {
        ESP_LOGI(TAG, "取消订阅成功: %s", topic.c_str());
    } else {
        ESP_LOGE(TAG, "取消订阅失败: %s", topic.c_str());
    }
    
    return success; // esp_mqtt_client_unsubscribe 错误时返回 -1
}

// 检查是否已连接
bool EspMqttImpl::IsConnected() {
    return is_connected_;
}

// --- 事件处理函数（由 internal_event_handler 调用）---
// 处理连接成功事件
void EspMqttImpl::handle_connected(esp_mqtt_event_handle_t const event) {
    is_connected_ = true; // 设置连接状态为 true
    
    if (on_connected_callback_) { // 如果设置了连接成功回调函数
        on_connected_callback_(); // 调用回调函数
    }
    
    ESP_LOGI(TAG, "MQTT连接成功");
}

// 处理断开连接事件
void EspMqttImpl::handle_disconnected(esp_mqtt_event_handle_t const event) {
    is_connected_ = false; // 设置连接状态为 false
    
    if (on_disconnected_callback_) { // 如果设置了断开连接回调函数
        on_disconnected_callback_(); // 调用回调函数
    }
    
    ESP_LOGI(TAG, "MQTT连接断开");
}

// 处理收到数据事件
void EspMqttImpl::handle_data(esp_mqtt_event_handle_t const event) {
    std::string topic(event->topic, event->topic_len); // 获取主题
    std::string payload(event->data, event->data_len); // 获取负载数据
    
    ESP_LOGI(TAG, "收到MQTT消息: %s", topic.c_str());
    
    if (on_message_callback_) { // 如果设置了收到消息回调函数
        on_message_callback_(topic, payload); // 调用回调函数
    }
}

// 处理订阅成功事件
void EspMqttImpl::handle_subscribed(esp_mqtt_event_handle_t event) {
    ESP_LOGI(TAG, "主题订阅确认 - ID: %d", event->msg_id);
    // 用户界面没有订阅成功的回调
}

// 处理取消订阅成功事件
void EspMqttImpl::handle_unsubscribed(esp_mqtt_event_handle_t event) {
    ESP_LOGI(TAG, "取消订阅确认 - ID: %d", event->msg_id);
    // 用户界面没有取消订阅的回调
}

// 处理发布成功事件
void EspMqttImpl::handle_published(esp_mqtt_event_handle_t event) {
    ESP_LOGI(TAG, "消息发布确认 - ID: %d", event->msg_id);
    // 用户界面没有发布成功的回调
}

// 处理错误事件
void EspMqttImpl::handle_error(esp_mqtt_event_handle_t event) {
    if (event->error_handle) { // 如果有错误句柄
        ESP_LOGE(TAG, "Last error code: 0x%x", event->error_handle->error_type); // 打印最后一个错误代码
        if (event->error_handle->error_type == MQTT_ERROR_TYPE_ESP_TLS) { // 如果是 ESP_TLS 错误
            ESP_LOGE(TAG, "Last error esp_tls_stack_err: 0x%x", event->error_handle->esp_tls_stack_err); // 打印 ESP_TLS 堆栈错误
            ESP_LOGE(TAG, "Last error esp_tls_cert_verify_flags: 0x%x", event->error_handle->esp_tls_cert_verify_flags); // 打印 ESP_TLS 证书验证标志
        } else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) { // 如果是连接被拒绝错误
            ESP_LOGE(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code); // 打印连接被拒绝错误代码
        } else { // 其他未知错误类型
            ESP_LOGE(TAG, "Unknown error type: 0x%x", event->error_handle->error_type); // 打印未知错误类型
        }
        if (event->error_handle->esp_transport_sock_errno != 0) { // 如果传输层套接字错误号不为0
             ESP_LOGE(TAG, "Last error esp_transport_sock_errno: %d (%s)", event->error_handle->esp_transport_sock_errno, strerror(event->error_handle->esp_transport_sock_errno)); // 打印传输层套接字错误
        }
    }
    
    ESP_LOGE(TAG, "MQTT错误事件");
    // 如果错误导致断开连接，is_connected_ 应设置为 false。
    // 通常在 ERROR 事件之后会跟随 DISCONNECTED 事件（如果连接丢失）。
    // 但是，如果我们想确定，也可以在这里设置 is_connected_ = false。
    // 目前，依赖于随后的 DISCONNECTED 事件。
}